import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import java.util.Stack;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

@SuppressWarnings("serial")
public class THMain extends JFrame {

	private class Block {

		int width;
		int height;
		int nr;
		Color color;

		Block(int w, int n) {
			width = w;
			height = 20;
			nr = n;
			color = new Color(random.nextInt(0xffffff));
		}
	}

	private int n;
	private int moves=0;
	private int windowheight=300;
	private int windowwidth =600;
	private Random random = new Random();
	Stack<Block> peg_a;
	Stack<Block> peg_b;
	Stack<Block> peg_c;

	THMain() {

		String userinput = JOptionPane.showInputDialog(null,
				"Palun sisesta soovitud torni 'kõrgus' (n)", "Hanoi Torn",
				JOptionPane.INFORMATION_MESSAGE);

		try {
			n = Integer.parseInt(userinput);
			if (n < 1)
				throw new NumberFormatException();

			setTitle("Hanoi Torn (c) Karl Puusepp");
			setDefaultCloseOperation(EXIT_ON_CLOSE);
			setSize(windowwidth, windowheight);
			if (n > 13) {
				windowheight+=(n-13)*20+10;
				setSize(windowwidth, windowheight);
			}
				
			setLocationRelativeTo(null);
			setVisible(true);

			// create three pegs
			peg_a = new Stack<Block>();
			peg_b = new Stack<Block>();
			peg_c = new Stack<Block>();

			// add n blocks to first peg
			for (int i = 0; i < n; i++) {
				peg_a.push(new Block(n*10 - i * 10, i));
			}

			solve();

		} catch (NumberFormatException e) {
			JOptionPane.showMessageDialog(null, "Sisendiviga!", "Hanoi Torn",
					JOptionPane.INFORMATION_MESSAGE);
		}

	}

	void solve() {

		while (!peg_a.isEmpty() || !peg_b.isEmpty()) {

			makeLegalMoveBetween(peg_a, (n % 2 == 0) ? peg_b : peg_c);
			animate();
			if (peg_c.size() == n)
				break;

			makeLegalMoveBetween(peg_a, (n % 2 == 0) ? peg_c : peg_b);
			animate();
			
			makeLegalMoveBetween(peg_b, peg_c);
			animate();
		}
		
		JOptionPane.showMessageDialog(null, 
				"Lahendatud "+moves+" käiguga. Lühim lahendus kasutab 2**n-1 ehk "+(Math.pow(2, n)-1)+ " käiku.", "Hanoi Torn",
				JOptionPane.INFORMATION_MESSAGE);
		
	}

	void makeLegalMoveBetween(Stack<Block> x, Stack<Block> y) {

		moves++;
		
		if (x.isEmpty()) {
			x.push(y.pop());
		} else if (y.isEmpty()) {
			y.push(x.pop());
		} else if (x.peek().nr < y.peek().nr)
			x.push(y.pop()); // x has larger disk
		else {
			y.push(x.pop());
		}

	}
	
	public void animate() {
		try {
			Thread.sleep(200); // ANIMATION CONSTANT
		} catch (InterruptedException e) {
			
		}
		this.repaint();
		
	}

	@Override
	public void paint(Graphics g) {
		int x = 100;
		int y = windowheight - 40;
		
		g.setColor(Color.DARK_GRAY); // background
		g.fillRect(0, 0, windowwidth, windowheight);
		
		drawPeg(peg_a, g, x, y);
		drawPeg(peg_b, g, x+180, y);
		drawPeg(peg_c, g, x+180+180, y);
		
	}
	
	private void drawPeg(Stack<Block> peg, Graphics g, int x, int y) {
		
		for (Block b : peg) {
			g.setColor(b.color);
			g.fillRect(x, y, b.width, b.height);
			y-=20;
		}
	}

	public static void main(String[] args) {
		new THMain();
	}
}
